using System;
using System.Globalization;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Markup;
using System.Reflection;
namespace System.Windows.Interactivity
{
    /// <summary>
    /// Represents an object that can invoke Actions conditionally.
    /// </summary>
    /// <remarks>This is an infrastructure class. Trigger authors should derive from Trigger&lt;T&gt; instead of this class.</remarks>
    [ContentProperty(Name = "Actions")]
    public abstract class TriggerBase : FrameworkElement, IAttachedObject
    {
        private DependencyObject associatedObject;
        private Type associatedObjectTypeConstraint;
        public static readonly DependencyProperty ActionsProperty = DependencyProperty.Register("Actions", typeof(TriggerActionCollection), typeof(TriggerBase), new PropertyMetadata(null));
        /// <summary>
        /// Event handler for registering to PreviewInvoke.
        /// </summary>
        public event EventHandler<PreviewInvokeEventArgs> PreviewInvoke;
        /// <summary>
        /// Gets the object to which the trigger is attached.
        /// </summary>
        /// <value>The associated object.</value>
        protected DependencyObject AssociatedObject
        {
            get
            {
                return this.associatedObject;
            }
        }
        /// <summary>
        /// Gets the type constraint of the associated object.
        /// </summary>
        /// <value>The associated object type constraint.</value>
        protected virtual Type AssociatedObjectTypeConstraint
        {
            get
            {
                return this.associatedObjectTypeConstraint;
            }
        }
        /// <summary>
        /// Gets the actions associated with this trigger.
        /// </summary>
        /// <value>The actions associated with this trigger.</value>
        public TriggerActionCollection Actions
        {
            get
            {
                return (TriggerActionCollection)base.GetValue(TriggerBase.ActionsProperty);
            }
        }
        /// <summary>
        /// Gets the associated object.
        /// </summary>
        /// <value>The associated object.</value>
        DependencyObject IAttachedObject.AssociatedObject
        {
            get
            {
                return this.AssociatedObject;
            }
        }
        internal TriggerBase(Type associatedObjectTypeConstraint)
        {
            this.associatedObjectTypeConstraint = associatedObjectTypeConstraint;
            TriggerActionCollection value = new TriggerActionCollection();
            base.SetValue(TriggerBase.ActionsProperty, value);
        }
        /// <summary>
        /// Invoke all actions associated with this trigger.
        /// </summary>
        /// <remarks>Derived classes should call this to fire the trigger.</remarks>
        protected void InvokeActions(object parameter)
        {
            if (this.PreviewInvoke != null)
            {
                PreviewInvokeEventArgs previewInvokeEventArgs = new PreviewInvokeEventArgs();
                this.PreviewInvoke(this, previewInvokeEventArgs);
                if (previewInvokeEventArgs.Cancelling)
                {
                    return;
                }
            }
            foreach (TriggerAction current in this.Actions)
            {
                current.CallInvoke(parameter);
            }
        }
        /// <summary>
        /// Called after the trigger is attached to an AssociatedObject.
        /// </summary>
        protected virtual void OnAttached()
        {
        }
        /// <summary>
        /// Called when the trigger is being detached from its AssociatedObject, but before it has actually occurred.
        /// </summary>
        protected virtual void OnDetaching()
        {
        }
        /// <summary>
        /// Creates a new instance of the TriggerBase derived class.
        /// </summary>
        /// <returns>The new instance.</returns>
        //protected override Freezable CreateInstanceCore()
        //{
        //    Type type = base.GetType();
        //    return (Freezable)Activator.CreateInstance(type);
        //}
        /// <summary>
        /// Attaches to the specified object.
        /// </summary>
        /// <param name="dependencyObject">The object to attach to.</param>
        /// <exception cref="T:System.InvalidOperationException">Cannot host the same trigger on more than one object at a time.</exception>
        /// <exception cref="T:System.InvalidOperationException">dependencyObject does not satisfy the trigger type constraint.</exception>
        public void Attach(DependencyObject dependencyObject)
        {
            if (dependencyObject != this.AssociatedObject)
            {
                if (this.AssociatedObject != null)
                {
                    throw new InvalidOperationException("CannotHostTriggerMultipleTimesExceptionMessage");
                }
                if (dependencyObject != null && !this.AssociatedObjectTypeConstraint.GetTypeInfo().IsAssignableFrom(dependencyObject.GetType().GetTypeInfo()))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "TypeConstraintViolatedExceptionMessage", new object[]
					{
						base.GetType().Name,
						dependencyObject.GetType().Name,
						this.AssociatedObjectTypeConstraint.Name
					}));
                }
                this.associatedObject = dependencyObject;
                this.Actions.Attach(dependencyObject);
                this.OnAttached();
            }
        }
        /// <summary>
        /// Detaches this instance from its associated object.
        /// </summary>
        public void Detach()
        {
            this.OnDetaching();
            this.associatedObject = null;
            this.Actions.Detach();
        }
    }
}
